package Lib3d;


import java.nio.FloatBuffer;
import java.util.Arrays;

/**
 * Classe repr�sentant un vecteur � trois dimensions
 * 
 * @author flamarch
 * 
 */
public class Vector3d {

    protected float[] m_coordinates;

    /**
     * Construction d'un vecteur � 3 dimensions
     * 
     * @param x
     * @param y
     * @param z
     */
    public Vector3d(final float x, final float y, final float z) {
        this.m_coordinates = new float[3];
        this.m_coordinates[0] = x;
        this.m_coordinates[1] = y;
        this.m_coordinates[2] = z;
    }

    /**
     * Addition de deux vecteurs
     * 
     * @param v
     * @param v2
     * @return
     */
    public static Vector3d add(final Vector3d v, final Vector3d v2) {
        return new Vector3d(v.m_coordinates[0] + v2.m_coordinates[0], v.m_coordinates[1]
                + v2.m_coordinates[1], v.m_coordinates[2] + v2.m_coordinates[2]);
    }

    /**
     * Produit scalaire entre deux vecteurs
     * 
     * @param v
     * @param v2
     * @return
     */
    public static float dot(final Vector3d v, final Vector3d v2) {
        float result = 0.0f;
        for (int cpt = 0; cpt < 3; ++cpt) {
            result += v.m_coordinates[cpt] * v2.m_coordinates[cpt];
        }
        return result;
    }

    /**
     * Multiplication vecteur / scalaire
     * 
     * @param v
     * @param value
     * @return
     */
    public static Vector3d mul(final Vector3d v, final float value) {
        return new Vector3d(v.m_coordinates[0] * value, v.m_coordinates[1] * value,
                v.m_coordinates[2] * value);
    }

    /**
     * Multiplication coordonn�e par coordonn�e de deux vecteurs 3D
     * 
     * @param v
     * @param v2
     * @return
     */
    public static Vector3d mul(final Vector3d v, final Vector3d v2) {
        return new Vector3d(v.m_coordinates[0] * v2.m_coordinates[0], v.m_coordinates[1]
                * v2.m_coordinates[1], v.m_coordinates[2] * v2.m_coordinates[2]);
    }

    /**
     * Multiplication vecteur / vecteur
     * 
     * @param u
     * @param v
     * @return
     */
    public static Vector3d mulVector3d(final Vector3d u, final Vector3d v) {
        final Vector3d w = new Vector3d(0, 0, 0);
        w.m_coordinates[0] = u.m_coordinates[1] * v.m_coordinates[2] - u.m_coordinates[2]
                * v.m_coordinates[1];
        w.m_coordinates[1] = u.m_coordinates[2] * v.m_coordinates[0] - u.m_coordinates[0]
                * v.m_coordinates[2];
        w.m_coordinates[2] = u.m_coordinates[0] * v.m_coordinates[1] - u.m_coordinates[1]
                * v.m_coordinates[0];
        return w;
    }

    /**
     * Renvoie l'oppos� du vecteur
     * 
     * @param v
     * @return
     */
    public static Vector3d neg(final Vector3d v) {
        return new Vector3d(-v.m_coordinates[0], -v.m_coordinates[1], -v.m_coordinates[2]);
    }

    /**
     * Soustraction de deux vecteurs
     * 
     * @param v
     * @param v2
     * @return
     */
    public static Vector3d sub(final Vector3d v, final Vector3d v2) {
        return Vector3d.add(v, Vector3d.neg(v2));
    }

    public float get(final int dimension) {
        return this.m_coordinates[dimension];
    }

    /**
     * Calcul la normale d'un vecteur
     * 
     * @return
     */
    public Vector3d getNormal() {
        final float l = this.length();
        if (l == 0.0f) {
            return null;
        }
        final float x = this.m_coordinates[0], y = this.m_coordinates[1], z = this.m_coordinates[2];
        return new Vector3d(x / l, y / l, z / l);
    }

    /**
     * Calcul de la norme d'un vecteur
     * 
     * @return
     */
    public float length() {
        return (float) Math.sqrt((this.m_coordinates[0] * this.m_coordinates[0])
                + (this.m_coordinates[1] * this.m_coordinates[1])
                + (this.m_coordinates[2] * this.m_coordinates[2]));
    }

    /**
     * Converti cet objet en FloatBuffer pour la compatibilit� avec l'API openGL
     * 
     * @return
     */
    public FloatBuffer toBuffer() {
        return FloatBuffer.wrap(this.m_coordinates);
    }

    @Override
    public String toString() {
        return "Vector3d " + Arrays.toString(this.m_coordinates);
    }

}